﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace HF
{
    /// <summary>
    /// <see cref="HExpr"/> 静态扩展方法类
    /// </summary>
    public static class HExprExt
    {
        /// <summary>
        /// 获取对象的属性值或成员值
        /// </summary>
        /// <param name="source">待获取值的对象</param>
        /// <param name="name">属性名或成员名,区分大小写</param>
        /// <returns>返回获取到的值</returns>
        public static object GetValueExpr(this object source, string name)
        {
            HExpr.Property.Reader.Complice(source.GetType(), name, out var read, out var _);
            var result = read(source);
            return result;
        }

        /// <summary>
        /// 获取对象的索引属性值
        /// </summary>
        /// <param name="source">待获取值的对象</param>
        /// <param name="name">属性名或成员名,区分大小写</param>
        /// <param name="param">索引参数列表</param>
        /// <returns>返回获取到的值</returns>
        public static object GetValueExpr(this object source, object[] param)
        {
            var types = param == null || param.Length == 0 ?
                Type.EmptyTypes :
                param.Select(v => v.GetType()).ToArray();

            HExpr.Property.Reader.Complice(source.GetType(), types, out var read, out var _);
            var result = read(source, param);
            return result;
        }

        /// <summary>
        /// 设置对象的属性值或成员值,包括私有
        /// </summary>
        /// <param name="source">待设置的对象</param>
        /// <param name="name">属性名或成员名,区分大小写</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static object SetValueExpr(this object source, string name, object value)
        {
            HExpr.Property.Writer.Complice(source.GetType(), name, out var write, out var _);
            write(source, value);
            return source;
        }

        /// <summary>
        /// 设置对象的索引属性值，包括私有的索引属性
        /// </summary>
        /// <param name="source">待设置的对象</param>
        /// <param name="value">值</param>
        /// <param name="param">索引参数</param>
        /// <returns></returns>
        public static object SetValueExpr(this object source, object value, object[] param)
        {
            var types = param == null || param.Length == 0 ?
                Type.EmptyTypes :
                param.Select(v => v.GetType()).ToArray();

            HExpr.Property.Writer.Complice(source.GetType(), types, out var write, out var _);
            write(source, param, value);
            return source;
        }

        /// <summary>
        /// 读取对象字段值包含(静态对象、私有字段)
        /// </summary>
        /// <param name="source">字段信息</param>
        /// <param name="instance">实体对象, 静态对象参数可为 <see langword="null"/></param>
        /// <returns></returns>
        public static object GetValueExpr(this MemberInfo source, object instance, params object[] args)
        {
            if (args != null && args.Length > 0)
            {
                var types = source is PropertyInfo pros ?
                    pros.GetIndexParameters().Select(v => v.ParameterType).ToArray() :
                    args.Select(v => v.GetType()).ToArray();

                HExpr.Property.Reader.Complice(source.DeclaringType, types, out var read, out var _);
                var result = read(instance, args);
                return result;
            }
            else
            {
                HExpr.Property.Reader.Complice(source.DeclaringType, source.Name, out var read, out var _);
                var result = read(instance);
                return result;
            }
        }

        /// <summary>
        /// 设置对象字段值，包含(静态对象、私有字段)
        /// </summary>
        /// <param name="source">字段信息</param>
        /// <param name="instance">实体对象, 静态对象参数可为 <see langword="null"/></param>
        /// <param name="value">待设置的值</param>
        public static void SetValueExpr(this MemberInfo source, object instance, object value, params object[] index)
        {
            if (index != null && index.Length > 0)
            {
                var types = source is PropertyInfo prs ?
                    prs.GetIndexParameters().Select(v => v.ParameterType).ToArray() :
                    index.Select(v => v.GetType()).ToArray();
                HExpr.Property.Writer.Complice(source.DeclaringType, types, out var write, out var _);
                write(instance, index, value);
            }
            else
            {
                HExpr.Property.Writer.Complice(source.DeclaringType, source.Name, out var write, out var _);
                write(instance, value);
            }
        }

        /// <summary>
        /// 调用对象方法
        /// </summary>
        /// <param name="source">方法信息</param>
        /// <param name="instance">实体对象, 静态对象参数可为 <see langword="null"/></param>
        /// <param name="args">参数集合</param>
        /// <returns></returns>
        public static object InvokeExpr(this MethodInfo source, object instance, object[] args)
        {
            HExpr.Method.Complice(source, out var func, out var _);
            return func(instance, args);
        }
    }
}
